home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume18 / elm2.2 / part11 < prev    next >
Encoding:
Internet Message Format  |  1989-04-12  |  49.2 KB

  1. Subject:  v18i090:  Elm mail system, release 2.2, Part11/24
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: dsinc!syd@uunet.UU.NET (Syd Weinstein)
  7. Posting-number: Volume 18, Issue 90
  8. Archive-name: elm2.2/part11
  9.  
  10. #!/bin/sh
  11. # this is part 11 of a multipart archive
  12. # do not concatenate these parts, unpack them in order with /bin/sh
  13. # file src/addr_util.c continued
  14. #
  15. CurArch=11
  16. if test ! -r s2_seq_.tmp
  17. then echo "Please unpack part 1 first!"
  18.      exit 1; fi
  19. ( read Scheck
  20.   if test "$Scheck" != $CurArch
  21.   then echo "Please unpack part $Scheck next!"
  22.        exit 1;
  23.   else exit 0; fi
  24. ) < s2_seq_.tmp || exit 1
  25. echo "x - Continuing file src/addr_util.c"
  26. sed 's/^X//' << 'SHAR_EOF' >> src/addr_util.c
  27. X/**
  28. X          get_return_name(address, mail_to, FALSE);
  29. X**/
  30. X        }
  31. X
  32. X        bufptr = (char *) NULL;    /* set to null */
  33. X      }
  34. X    }
  35. X
  36. X    return;
  37. X}
  38. SHAR_EOF
  39. echo "File src/addr_util.c is complete"
  40. chmod 0444 src/addr_util.c || echo "restore of src/addr_util.c fails"
  41. echo "x - extracting src/alias.c (Text)"
  42. sed 's/^X//' << 'SHAR_EOF' > src/alias.c &&
  43. X
  44. Xstatic char rcsid[] = "@(#)$Id: alias.c,v 2.14 89/03/30 10:25:28 syd Exp $";
  45. X
  46. X/*******************************************************************************
  47. X *  The Elm Mail System  -  $Revision: 2.14 $   $State: Exp $
  48. X *
  49. X *             Copyright (c) 1986, 1987 Dave Taylor
  50. X *             Copyright (c) 1988, 1989 USENET Community Trust
  51. X *******************************************************************************
  52. X * Bug reports, patches, comments, suggestions should be sent to:
  53. X *
  54. X *    Syd Weinstein, Elm Coordinator
  55. X *    elm@dsinc.UUCP            dsinc!elm
  56. X *
  57. X *******************************************************************************
  58. X * $Log:    alias.c,v $
  59. X * Revision 2.14  89/03/30  10:25:28  syd
  60. X * Check variable value for being in valid range before using to prevent
  61. X * segmentation violation.
  62. X * From: Rob Bernardo <rob@pbhyf.PacBell.COM>
  63. X * 
  64. X * Revision 2.13  89/03/25  21:45:42  syd
  65. X * Initial 2.2 Release checkin
  66. X * 
  67. X *
  68. X ******************************************************************************/
  69. X
  70. X/** This file contains alias stuff
  71. X
  72. X**/
  73. X
  74. X#include "headers.h"
  75. X#include <errno.h>
  76. X
  77. X#ifdef BSD
  78. X#undef        tolower
  79. X#endif
  80. X
  81. X#define    ECHOIT    1     /* echo on for prompting */
  82. X
  83. Xchar *expand_group(), *get_alias_address(), *expand_system(), *get_token();
  84. Xchar *error_name(), *error_description(), *strip_parens();
  85. X
  86. Xunsigned long sleep();
  87. X
  88. Xextern int errno;
  89. X
  90. Xextern int  findnode_has_been_initialized;
  91. X
  92. Xread_alias_files()
  93. X{
  94. X    /** read the system and user alias files, if present.
  95. X        Set the flags 'systemfiles' and 'userfiles' accordingly.
  96. X    **/
  97. X
  98. X    char fname[SLEN];
  99. X    int  hash;
  100. X
  101. X    if ((hash = open(system_hash_file, O_RDONLY)) == -1) {
  102. X      dprint(2, (debugfile,
  103. X        "Warning: Can't read system hash file %s\n", system_hash_file));
  104. X      goto user;
  105. X    }
  106. X
  107. X    read(hash, (char *) system_hash_table, sizeof system_hash_table);
  108. X    close(hash);
  109. X
  110. X    /* and data file opened.. */
  111. X
  112. X    if ((system_data = open(system_data_file, O_RDONLY)) == -1) {
  113. X     dprint(1, (debugfile,
  114. X               "Warning: Can't read system data file %s\n", system_data_file));
  115. X      goto user;
  116. X    }
  117. X
  118. X    system_files++;    /* got the system files! */
  119. X
  120. Xuser:   sprintf(fname,  "%s/%s", home, ALIAS_HASH); 
  121. X
  122. X    if ((hash = open(fname, O_RDONLY)) == -1) {
  123. X     dprint(2,(debugfile, "Warning: Can't read user hash file %s\n",
  124. X          fname));
  125. X      return;
  126. X    }
  127. X
  128. X    read(hash, (char *) user_hash_table, sizeof user_hash_table);
  129. X    close(hash);
  130. X
  131. X    sprintf(fname,  "%s/%s", home, ALIAS_DATA); 
  132. X
  133. X    if ((user_data = open(fname, O_RDONLY)) == -1) {
  134. X      dprint(1, (debugfile,
  135. X             "Warning: can't read user data file %s\n", fname));
  136. X      return;
  137. X    }
  138. X
  139. X    user_files++;    /* got user files too! */
  140. X}
  141. X
  142. Xint
  143. Xadd_alias()
  144. X{
  145. X    /** add an alias to the user alias text file.  Return zero 
  146. X        if alias not added in actuality **/
  147. X
  148. X    char name[SLEN], *address, address1[LONG_STRING], buffer[LONG_STRING];
  149. X    char comment[SLEN], ch;
  150. X    char *strcpy();
  151. X
  152. X    strcpy(buffer, "Enter alias name: ");
  153. X    PutLine0(LINES-2,0, buffer);
  154. X    CleartoEOLN();
  155. X    *name = '\0';
  156. X    optionally_enter(name, LINES-2, strlen(buffer), FALSE, FALSE);
  157. X    if (strlen(name) == 0) 
  158. X      return(0);
  159. X    if ((address = get_alias_address(name, 0, 0)) != NULL) {
  160. X      dprint(3, (debugfile, 
  161. X         "Attempt to add a duplicate alias [%s] in add_alias\n",
  162. X         address)); 
  163. X      if (address[0] == '!') {
  164. X        address[0] = ' ';
  165. X        error1("Already a group with name %s.", address);
  166. X      }
  167. X      else
  168. X        error1("Already an alias for %s.", address);
  169. X      return(0);
  170. X    }
  171. X
  172. X    sprintf(buffer, "Enter full name for %s: ", name);
  173. X    PutLine0(LINES-2,0, buffer);
  174. X    CleartoEOLN();
  175. X    *comment = '\0';
  176. X    optionally_enter(comment, LINES-2, strlen(buffer), FALSE, FALSE);
  177. X    if (strlen(comment) == 0) strcpy(comment, name);  
  178. X
  179. X    sprintf(buffer, "Enter address for %s: ", name);
  180. X    PutLine0(LINES-2,0, buffer);
  181. X    CleartoEOLN();
  182. X    *address1 = '\0';
  183. X    optionally_enter(address1, LINES-2, strlen(buffer), FALSE, FALSE);
  184. X    Raw(ON);
  185. X    if (strlen(address1) == 0) {
  186. X      error("No address specified!");
  187. X      return(0);
  188. X    }
  189. X    PutLine3(LINES-2,0,"%s (%s) = %s", comment, name, address1);
  190. X    CleartoEOLN();
  191. X    if((ch = want_to("Accept new alias? (y/n) ",'y')) == 'y')
  192. X      add_to_alias_text(name, comment, address1);
  193. X    ClearLine(LINES-2);
  194. X    return(ch == 'y' ? 1 : 0);
  195. X}
  196. X
  197. Xint
  198. Xdelete_alias()
  199. X{
  200. X    /** delete an alias from the user alias text file.  Return zero 
  201. X        if alias not deleted in actuality **/
  202. X
  203. X    char name[SLEN], *address, buffer[LONG_STRING];
  204. X    char *strcpy();
  205. X
  206. X    strcpy(buffer, "Enter alias name for deletion: ");
  207. X    PutLine0(LINES-2,0, buffer);
  208. X    CleartoEOLN();
  209. X    *name = '\0';
  210. X    optionally_enter(name, LINES-2, strlen(buffer), FALSE, FALSE);
  211. X    if (strlen(name) == 0) 
  212. X      return(0);
  213. X        if ((address = get_alias_address(name, 0, 0))!=NULL)
  214. X        {
  215. X                if (address[0] == '!')
  216. X                {
  217. X                  address[0] = ' ';
  218. X                  PutLine1(LINES-1,0,"Group alias: %-60.60s", address);
  219. X                  CleartoEOLN();
  220. X            }
  221. X        else
  222. X          PutLine1(LINES-1,0,"Aliased address: %-60.60s", address);
  223. X    }
  224. X        else 
  225. X    {
  226. X          dprint(3, (debugfile, 
  227. X         "Attempt to delete a non-existent alias [%s] in delete_alias\n",
  228. X         name)); 
  229. X         error1("No alias for %s.", name);
  230. X          return(0);
  231. X    }
  232. X    if (want_to("Delete this alias? (y/n) ", 'y') == 'y')
  233. X    {
  234. X        if (!delete_from_alias_text(name))
  235. X        {
  236. X            CleartoEOS();
  237. X            return(1);
  238. X        }
  239. X    }
  240. X    CleartoEOS();
  241. X    return(0);
  242. X}
  243. X
  244. Xint
  245. Xadd_current_alias()
  246. X{
  247. X    /** alias the current message to the specified name and
  248. X        add it to the alias text file, for processing as
  249. X        the user leaves the program.  Returns non-zero iff
  250. X        alias actually added to file **/
  251. X
  252. X    char name[SLEN], address1[LONG_STRING], buffer[LONG_STRING], *address;
  253. X    char comment[SLEN], ch;
  254. X    struct header_rec *current_header;
  255. X
  256. X    if (current == 0) {
  257. X     dprint(4, (debugfile, 
  258. X        "Add current alias called without any current message!\n"));
  259. X     error("No message to alias to!");
  260. X     return(0);
  261. X    }
  262. X    current_header = headers[current - 1];
  263. X    
  264. X    strcpy(buffer, "Current message address aliased to: ");
  265. X    PutLine0(LINES-2,0, buffer);
  266. X    CleartoEOLN();
  267. X    *name = '\0';
  268. X    optionally_enter(name, LINES-2, strlen(buffer), FALSE, FALSE);
  269. X    if (strlen(name) == 0)    /* cancelled... */
  270. X      return(0);
  271. X    if ((address = get_alias_address(name, 0, 0)) != NULL) {
  272. X     dprint(3, (debugfile,
  273. X             "Attempt to add a duplicate alias [%s] in add_current_alias\n",
  274. X         address)); 
  275. X      if (address[1] == '!') {
  276. X        address[0] = ' ';
  277. X        error1("Already a group with name %s.", address);
  278. X      }
  279. X      else 
  280. X        error1("Already an alias for %s.", address); 
  281. X          return(0);
  282. X    }
  283. X
  284. X    sprintf(buffer, "Enter full name for %s: ", name);
  285. X    PutLine0(LINES-2,0, buffer);
  286. X    CleartoEOLN();
  287. X
  288. X    /* use full name in current message for default comment */
  289. X    tail_of(current_header->from, comment, current_header->to);
  290. X    if(strchr(comment, '!') || strchr(comment, '@'))
  291. X      /* never mind - it's an address not a full name */
  292. X      *comment = '\0';
  293. X
  294. X    optionally_enter(comment, LINES-2, strlen(buffer), FALSE, FALSE);
  295. X
  296. X    /* grab the return address of this message */
  297. X    get_return(address1, current-1);
  298. X
  299. X    /* if this is from the use (a saved copy) use the 'to' addrs instead */
  300. X    get_return_name(address1, buffer, TRUE);
  301. X    if(strcmp(buffer, username) == 0)
  302. X      get_existing_address(address1, current-1);
  303. X
  304. X    strcpy(address1, strip_parens(address1));    /* remove parens! */
  305. X#ifdef OPTIMIZE_RETURN
  306. X    optimize_return(address1);
  307. X#endif
  308. X    PutLine3(LINES-2,0,"%s (%s) = %s", comment, name, address1);
  309. X    CleartoEOLN();
  310. X    if((ch = want_to("Accept new alias? (y/n) ",'y')) == 'y')
  311. X      add_to_alias_text(name, comment, address1);
  312. X    ClearLine(LINES-2);
  313. X    return(ch == 'y' ? 1 : 0);
  314. X}
  315. X
  316. Xadd_to_alias_text(name, comment, address)
  317. Xchar *name, *comment, *address;
  318. X{
  319. X    /** Add the data to the user alias text file.  Return zero if we
  320. X        succeeded, 1 if not **/
  321. X    
  322. X    FILE *file;
  323. X    char fname[SLEN];
  324. X    
  325. X    sprintf(fname,"%s/%s", home, ALIAS_TEXT);
  326. X    
  327. X    save_file_stats(fname);
  328. X    if ((file = fopen(fname, "a")) == NULL) {
  329. X      dprint(2, (debugfile, 
  330. X         "Failure attempting to add alias to file %s within %s",
  331. X           fname, "add_to_alias_text"));
  332. X      dprint(2, (debugfile, "** %s - %s **\n", error_name(errno), 
  333. X           error_description(errno)));
  334. X      error1("Couldn't open %s to add new alias!", fname);
  335. X      return(1);
  336. X    }
  337. X
  338. X    fprintf(file,"%s = %s = %s\n", name, comment, address);
  339. X    fclose(file);
  340. X
  341. X    restore_file_stats(fname);
  342. X
  343. X    return(0);
  344. X}
  345. X
  346. Xdelete_from_alias_text(name)
  347. Xchar *name;
  348. X{
  349. X    /** Delete the data from the user alias text file.  Return zero if we
  350. X        succeeded, 1 if not **/
  351. X    
  352. X    FILE *file, *tmpfile;
  353. X    char fname[SLEN], tmpfname[SLEN];
  354. X    char line_in_file[SLEN+3+SLEN+3+LONG_STRING]; /* name = comment = address */
  355. X    char name_with_equals[SLEN+2];
  356. X
  357. X    strcpy(name_with_equals, name);
  358. X    strcat(name_with_equals, " ="); 
  359. X
  360. X    sprintf(fname,"%s/%s", home, ALIAS_TEXT);
  361. X    sprintf(tmpfname,"%s/%s.tmp", home, ALIAS_TEXT);
  362. X    
  363. X    save_file_stats(fname);
  364. X
  365. X    if ((file = fopen(fname, "r")) == NULL) {
  366. X      dprint(2, (debugfile, 
  367. X         "Failure attempting to delete alias from file %s within %s",
  368. X           fname, "delete_from_alias_text"));
  369. X      dprint(2, (debugfile, "** %s - %s **\n", error_name(errno), 
  370. X           error_description(errno)));
  371. X      error1("Couldn't open %s to delete alias!", fname);
  372. X      return(1);
  373. X    }
  374. X
  375. X    if ((tmpfile = fopen(tmpfname, "w")) == NULL) {
  376. X      dprint(2, (debugfile, 
  377. X         "Failure attempting to open temp file %s within %s",
  378. X           tmpfname, "delete_from_alias_text"));
  379. X      dprint(2, (debugfile, "** %s - %s **\n", error_name(errno), 
  380. X           error_description(errno)));
  381. X      error1("Couldn't open tempfile %s to delete alias!", tmpfname);
  382. X      return(1);
  383. X    }
  384. X
  385. X    while (fgets(line_in_file, sizeof(line_in_file), file) != (char *)NULL)
  386. X    {
  387. X        if (strncmp(name_with_equals, line_in_file,
  388. X                strlen(name_with_equals)) != 0)
  389. X            fprintf(tmpfile,"%s", line_in_file);
  390. X    }
  391. X    fclose(file);
  392. X    fclose(tmpfile);
  393. X    if (rename(tmpfname, fname) != 0)
  394. X    {
  395. X        error1("Couldn't rename tempfile %s after deleting alias!", tmpfname);
  396. X        return(1);
  397. X    }
  398. X
  399. X    restore_file_stats(fname);
  400. X
  401. X    return(0);
  402. X}
  403. X
  404. Xshow_alias_menu()
  405. X{
  406. X    MoveCursor(LINES-7,0); CleartoEOS();    
  407. X        
  408. X    PutLine0(LINES-7,COLUMNS-45, "Alias commands");
  409. X    Centerline(LINES-6,
  410. X      "a)lias current message, d)elete an alias, check a p)erson or s)ystem,");
  411. X    Centerline(LINES-5,
  412. X      "l)ist existing aliases, m)ake new alias, or r)eturn");
  413. X}
  414. X
  415. Xalias()
  416. X{
  417. X    /** work with alias commands... **/
  418. X    /** return non-0 if main part of screen overwritten, else 0 **/
  419. X
  420. X    char name[NLEN], *address, ch, buffer[SLEN];
  421. X    int  newaliases = 0, redraw = 0;
  422. X
  423. X    if (mini_menu)
  424. X      show_alias_menu();
  425. X
  426. X    /** now let's ensure that we've initialized everything! **/
  427. X
  428. X#ifndef DONT_TOUCH_ADDRESSES
  429. X    
  430. X    if (! findnode_has_been_initialized) {
  431. X      if (warnings)
  432. X        error("Initializing internal tables...");
  433. X#ifndef USE_DBM
  434. X      get_connections();
  435. X      open_domain_file();
  436. X#endif
  437. X      init_findnode();
  438. X      clear_error();
  439. X          findnode_has_been_initialized = TRUE;
  440. X    }
  441. X
  442. X#endif
  443. X
  444. X    define_softkeys(ALIAS);
  445. X
  446. X    while (1) {
  447. X      prompt("Alias: ");
  448. X      CleartoEOLN();
  449. X      ch = ReadCh();
  450. X      MoveCursor(LINES-1,0); CleartoEOS();
  451. X      
  452. X      dprint(3, (debugfile, "\n-- Alias command: %c\n\n", ch));
  453. X
  454. X      switch (tolower(ch)) {
  455. X        case '?': redraw += alias_help();            break;
  456. X
  457. X        case 'a': newaliases += add_current_alias();    break;
  458. X        case 'd': if (delete_alias()) install_aliases();    break;
  459. X        case 'l': display_aliases();
  460. X              redraw++;
  461. X              if (mini_menu) show_alias_menu();
  462. X              break;
  463. X        case 'm': newaliases += add_alias();         break;
  464. X
  465. X        case RETURN:
  466. X        case LINE_FEED:
  467. X        case 'q':
  468. X        case 'x':
  469. X        case 'r': if (newaliases) install_aliases();
  470. X              clear_error();
  471. X              return(redraw);
  472. X        case 'p': if (newaliases) 
  473. X            error("Warning: new aliases not installed yet!");
  474. X
  475. X              strcpy(buffer, "Check for person: ");
  476. X              PutLine0(LINES-2,0, buffer);
  477. X              CleartoEOLN();
  478. X              *name = '\0';
  479. X              optionally_enter(name, LINES-2, strlen(buffer),
  480. X            FALSE, FALSE);
  481. X
  482. X              if ((address = get_alias_address(name, 0, 0))!=NULL) {
  483. X                    if (address[0] == '!') {
  484. X                      address[0] = ' ';
  485. X                      PutLine1(LINES-1,0,"Group alias:%-60.60s", address);
  486. X                      CleartoEOLN();
  487. X                }
  488. X            else
  489. X              PutLine1(LINES-1,0,"Aliased address: %-60.60s", 
  490. X              address);
  491. X              }
  492. X                  else 
  493. X            error("Not found.");
  494. X              break;
  495. X
  496. X        case 's': strcpy(buffer, "Check for system: ");
  497. X              PutLine0(LINES-2,0, buffer);
  498. X              CleartoEOLN();
  499. X              *name = '\0';
  500. X              optionally_enter(name, LINES-2, strlen(buffer),
  501. X            FALSE, FALSE);
  502. X              if (talk_to(name)) 
  503. X#ifdef INTERNET
  504. X            PutLine1(LINES-1,0,
  505. X        "You have a direct connection. The address is USER@%s.", 
  506. X            name);
  507. X#else
  508. X            PutLine1(LINES-1,0,
  509. X        "You have a direct connection. The address is %s!USER.", 
  510. X            name);
  511. X#endif
  512. X              else {
  513. X                sprintf(buffer, "USER@%s", name);
  514. X#ifdef DONT_TOUCH_ADDRESSES
  515. X                 address = buffer;
  516. X#else
  517. X                 address = expand_system(buffer, FALSE);
  518. X#endif
  519. X                if (strlen(address) > strlen(name) + 7)
  520. X                  PutLine1(LINES-1,0,"Address is: %.65s", address);
  521. X                else
  522. X                  error1("Couldn't expand system %s.", name);
  523. X              }
  524. X              break;
  525. X
  526. X        case '@': strcpy(buffer, "Fully expand alias: ");
  527. X              PutLine0(LINES-2,0, buffer);
  528. X              CleartoEOS();
  529. X              *name = '\0';
  530. X              optionally_enter(name, LINES-2, strlen(buffer),
  531. X            FALSE, FALSE);
  532. X              if ((address = get_alias_address(name, 1, 0)) != NULL) {
  533. X                    ClearScreen();
  534. X            PutLine1(3,0,"Aliased address:\n\r%s", address);
  535. X                    PutLine0(LINES-1,0,"Press <return> to continue.");
  536. X            (void) getchar();
  537. X            redraw++;
  538. X              }
  539. X                  else 
  540. X            error("Not found.");
  541. X              if (mini_menu) show_alias_menu();
  542. X              break;
  543. X        default : error("Invalid input!");
  544. X      }
  545. X    }
  546. X}
  547. X
  548. Xinstall_aliases()
  549. X{
  550. X    /** run the 'newalias' program and update the
  551. X        aliases before going back to the main program! 
  552. X    **/
  553. X
  554. X
  555. X    error("Updating aliases...");
  556. X    sleep(2);
  557. X
  558. X    if (system_call(newalias, SH, FALSE) == 0) {
  559. X      error("Re-reading the database in...");
  560. X      sleep(2);
  561. X      read_alias_files();
  562. X      set_error("Aliases updated successfully.");
  563. X    }
  564. X    else
  565. X      set_error("'Newalias' failed.  Please check alias_text.");
  566. X}
  567. X
  568. Xalias_help()
  569. X{
  570. X    /** help section for the alias menu... **/
  571. X    /** return non-0 if main part of screen overwritten, else 0 */
  572. X    
  573. X    char ch;
  574. X    int  redraw=0;
  575. X
  576. X    MoveCursor(LINES-3, 0);    CleartoEOS();
  577. X
  578. X    if (! mini_menu)
  579. X      lower_prompt("Key you want help for: ");
  580. X    else {
  581. X      Centerline(LINES-3, 
  582. X"Enter key you want help for, '?' for list or '.' to leave help");
  583. X      lower_prompt("Key: ");
  584. X    }
  585. X
  586. X    while ((ch = ReadCh()) != '.') {
  587. X      ch = tolower(ch);
  588. X      switch(ch) {
  589. X        case '?' : display_helpfile(ALIAS_HELP);    
  590. X               redraw++;
  591. X                   if (mini_menu) show_alias_menu();
  592. X               return(redraw);
  593. X        case 'a': error(
  594. X        "a = Add (return) address of current message to alias database.");
  595. X              break;
  596. X        case 'd': error("d = Delete a user alias from alias database.");
  597. X              break;
  598. X        case 'l': error("l = List all aliases in database.");
  599. X              break;
  600. X        case 'm': error(
  601. X        "m = Make a new user alias, adding to alias database when done.");
  602. X              break;
  603. X
  604. X        case RETURN:
  605. X        case LINE_FEED:
  606. X        case 'q':
  607. X        case 'x':
  608. X        case 'r': error("Return from alias menu.");
  609. X                 break;
  610. X              
  611. X        case 'p': error("p = Check for a person in the alias database.");
  612. X              break;
  613. X    
  614. X        case 's': error(
  615. X        "s = Check for a system in the host routing/domain database.");
  616. X              break;
  617. X    
  618. X        default : error("That key isn't used in this section.");
  619. X                 break;
  620. X      }
  621. X      if (! mini_menu)
  622. X        lower_prompt("Key you want help for: ");
  623. X      else 
  624. X        lower_prompt("Key: ");
  625. X    }
  626. X    return(redraw);
  627. X}
  628. X
  629. Xdisplay_aliases()
  630. X{
  631. X    char fname[SLEN];
  632. X    
  633. X    sprintf(fname,"%s/%s", home, ALIAS_TEXT);
  634. X    display_file(fname);
  635. X    ClearScreen();
  636. X    return;
  637. X}
  638. SHAR_EOF
  639. chmod 0444 src/alias.c || echo "restore of src/alias.c fails"
  640. echo "x - extracting src/aliasdb.c (Text)"
  641. sed 's/^X//' << 'SHAR_EOF' > src/aliasdb.c &&
  642. X
  643. Xstatic char rcsid[] = "@(#)$Id: aliasdb.c,v 2.8 89/03/25 21:45:45 syd Exp $";
  644. X
  645. X/*******************************************************************************
  646. X *  The Elm Mail System  -  $Revision: 2.8 $   $State: Exp $
  647. X *
  648. X *             Copyright (c) 1986, 1987 Dave Taylor
  649. X *             Copyright (c) 1988, 1989 USENET Community Trust
  650. X *******************************************************************************
  651. X * Bug reports, patches, comments, suggestions should be sent to:
  652. X *
  653. X *    Syd Weinstein, Elm Coordinator
  654. X *    elm@dsinc.UUCP            dsinc!elm
  655. X *
  656. X *******************************************************************************
  657. X * $Log:    aliasdb.c,v $
  658. X * Revision 2.8  89/03/25  21:45:45  syd
  659. X * Initial 2.2 Release checkin
  660. X * 
  661. X *
  662. X ******************************************************************************/
  663. X
  664. X/** Alias database files...
  665. X
  666. X**/
  667. X
  668. X
  669. X#include "headers.h"
  670. X
  671. X#include <sys/types.h>
  672. X#include <sys/stat.h>
  673. X#include <errno.h>
  674. X
  675. Xextern int errno;
  676. X
  677. X#ifdef USE_DBM
  678. X# include <dbm.h>
  679. X#endif
  680. X
  681. X#define  absolute(x)        ((x) > 0 ? x : -(x))
  682. X
  683. Xchar *shift_lower(), *find_path_to(), *strcat(), *strcpy();
  684. Xunsigned long sleep();
  685. X
  686. Xint  findnode_has_been_initialized = FALSE;
  687. X
  688. Xfindnode(name, display_error)
  689. Xchar *name;
  690. Xint   display_error;
  691. X{
  692. X    /** break 'name' into machine!user or user@machine and then
  693. X        see if you can find 'machine' in the path database..
  694. X        If so, return name as the expanded address.  If not,
  695. X        return what was given to us!   If display_error, then
  696. X        do so...
  697. X    **/
  698. X
  699. X#ifndef DONT_TOUCH_ADDRESSES
  700. X    
  701. X    char   old_name[SLEN];
  702. X    char   address[SLEN];
  703. X
  704. X    if (strlen(name) == 0)
  705. X      return;
  706. X    
  707. X    if (! findnode_has_been_initialized) {
  708. X      if (warnings)
  709. X        error("Initializing internal tables...");
  710. X#ifndef USE_DBM
  711. X      get_connections();
  712. X      open_domain_file();
  713. X#endif
  714. X      init_findnode();
  715. X      clear_error();
  716. X          findnode_has_been_initialized = TRUE;
  717. X    }
  718. X
  719. X    strcpy(old_name, name);        /* save what we were given */
  720. X
  721. X    if (expand_site(name, address) == -1) {
  722. X          if (display_error && name[0] != '!') {
  723. X        dprint(3, (debugfile, "Couldn't expand host %s in address.\n",
  724. X                 name));
  725. X        if (! check_only && warnings) {
  726. X          error1("Couldn't expand system %s.", name);
  727. X          sleep(1);
  728. X        }
  729. X      }
  730. X      strcpy(name, old_name);    /* and restore... */
  731. X    }
  732. X    else
  733. X      strcpy(name, address);
  734. X#endif
  735. X    return;
  736. X}
  737. X
  738. Xint
  739. Xexpand_site(cryptic, expanded)
  740. Xchar *cryptic, *expanded;
  741. X{
  742. X
  743. X    /** Given an address of the form 'xyz@site' or 'site!xyz'
  744. X        return an address of the form <expanded address for site>
  745. X            with 'xyz' embedded according to the path database entry.
  746. X        Note that 'xyz' can be eiher a simple address (as in "joe")
  747. X        or a complex address (as in "joe%xerox.parc@Xerox.ARPA")!
  748. X        0 = found, -1 return means unknown site code 
  749. X    
  750. X        Modified to strip out parenthetical comments...
  751. X    **/
  752. X
  753. X#ifdef ACSNET
  754. X
  755. X    strcpy(expanded, cryptic);    /* fast and simple */
  756. X    return(0);
  757. X
  758. X#else
  759. X# ifdef USE_DBM
  760. X    datum  key, contents;
  761. X# endif
  762. X
  763. X    char   name[VERY_LONG_STRING], sitename[VERY_LONG_STRING], 
  764. X               temp[VERY_LONG_STRING], old_name[VERY_LONG_STRING],
  765. X           comment[LONG_STRING];
  766. X    char   *expand_domain(), *addr;
  767. X    register int i = 0, j = 0, in_parens = 0, domain_name;
  768. X
  769. X    strcpy(old_name, cryptic);    /* remember what we were given */
  770. X
  771. X    /** break down **/
  772. X
  773. X    /** first, rip out the comment, if any, noting nested parens **/
  774. X
  775. X    if ((i = chloc(cryptic, '(')) > -1) {
  776. X      comment[j++] = ' ';            /* leading space */
  777. X      do {
  778. X          switch(comment[j++] = cryptic[i++]) {
  779. X        case '(':    in_parens++;
  780. X            break;
  781. X        case ')':    in_parens--;
  782. X            break;
  783. X        }
  784. X      } while(in_parens && cryptic[i] != '\0');
  785. X      comment[j] = '\0';
  786. X
  787. X      /* and remove this from cryptic string too... */
  788. X      if (cryptic[(j = chloc(cryptic,'('))-1] == ' ')
  789. X        cryptic[j-1] = '\0';
  790. X      else
  791. X        cryptic[j] = '\0';
  792. X    }
  793. X    else
  794. X      comment[0] = '\0';
  795. X
  796. X    i = j = 0;    /* reset */
  797. X
  798. X    while (cryptic[i] != AT_SIGN && cryptic[i] != BANG && 
  799. X           cryptic[i] != '\0' && cryptic[i] != '(')
  800. X      sitename[j++] = cryptic[i++];
  801. X
  802. X    sitename[j++] = '\0';
  803. X
  804. X    j = 0;
  805. X    
  806. X    if (cryptic[i] == '\0') return(-1);    /* nothing to expand! */
  807. X
  808. X    domain_name = (cryptic[i] == AT_SIGN);
  809. X
  810. X    i++;
  811. X
  812. X    while (cryptic[i] != '\0' && cryptic[i] != '(' && 
  813. X               ! whitespace(cryptic[i]))
  814. X      name[j++] = cryptic[i++];
  815. X
  816. X    name[j] = '\0';
  817. X
  818. X    if (domain_name) {
  819. X      strcpy(temp, name);
  820. X      strcpy(name, sitename);
  821. X      strcpy(sitename, temp);
  822. X    }
  823. X
  824. X    dprint(5, (debugfile, "\nBroke address into '%s' @ '%s' '%s'\n\n",
  825. X        name, sitename, comment));
  826. X
  827. X#ifdef USE_DBM
  828. X
  829. X    if (size_of_pathfd == 0)
  830. X      return(-1);
  831. X
  832. X    key.dptr  = sitename;
  833. X    key.dsize = strlen(sitename) + 1;
  834. X
  835. X    contents = fetch(key);
  836. X
  837. X    if (contents.dptr == 0) 
  838. X      return(-1);            /* can't find it! */
  839. X
  840. X    sprintf(expanded, contents.dptr, name);
  841. X    strcat(expanded, " ");            /* add a single space... */
  842. X    strcat(expanded, comment);        /*    ...and add comment */
  843. X    return(0);
  844. X#endif
  845. X
  846. X#ifndef LOOK_CLOSE_AFTER_SEARCH
  847. X
  848. X    if (talk_to(sitename)) {
  849. X      strcpy(expanded, old_name);    /* restore! */
  850. X      return(0);
  851. X    }
  852. X#endif
  853. X
  854. X    if ((addr = find_path_to(sitename, TRUE)) == NULL) {
  855. X
  856. X#ifdef LOOK_CLOSE_AFTER_SEARCH
  857. X
  858. X        if (talk_to(sitename)) {
  859. X          strcpy(expanded, old_name);    /* restore! */
  860. X          return(0);
  861. X        }
  862. X        else
  863. X#endif
  864. X        if ((addr = expand_domain(cryptic)) != NULL) {
  865. X           strcpy(expanded, addr);    /* into THIS buffer */
  866. X           strcat(expanded, comment);    /* patch in comment */
  867. X           return(0);
  868. X        }
  869. X        else  if (size_of_pathfd == 0) {    /* no path database! */
  870. X          strcpy(expanded, old_name);    /* restore! */
  871. X          return(0);
  872. X        }
  873. X        else {                 /* We just can't get there! */
  874. X          strcpy(expanded, old_name);    /* restore! */
  875. X          return(-1);
  876. X        }
  877. X    }
  878. X    else {            /* search succeeded */
  879. X       sprintf(expanded, addr, name);
  880. X       strcat(expanded, comment);        /* add comment */
  881. X       return(0);
  882. X    }
  883. X#endif
  884. X}
  885. X
  886. Xint
  887. Xbinary_search(name, address)
  888. Xchar *name, *address;
  889. X{
  890. X    /* binary search file for name.  Return 0 if found, -1 if not */
  891. X
  892. X    char machine[40];
  893. X    register long first = 0, last, middle;
  894. X    register int  compare;
  895. X
  896. X    address[0] = '\0';
  897. X
  898. X    last = size_of_pathfd;
  899. X
  900. X    do {
  901. X
  902. X      middle = (long) ((first+last) / 2);
  903. X
  904. X      get_entry(machine, address, pathfd, middle);
  905. X
  906. X      compare = strcmp(name, machine);
  907. X
  908. X      if (compare < 0) 
  909. X        last = middle - 1;
  910. X      else if (compare == 0)
  911. X        return(0);
  912. X      else  /* greater */
  913. X        first = middle + 1; 
  914. X    } while (absolute(last) - absolute(first) > FIND_DELTA);
  915. X
  916. X    /* It could be that our target entry lies exactly at `first'.
  917. X     * Since get_entry() compares at the entry beginning after
  918. X     * the passed offset (unless it's 0), we need to decrement it
  919. X     * (unless it's 0), and give it one more try.
  920. X     */
  921. X    get_entry(machine, address, pathfd, (first == 0L ? first : --first));
  922. X    compare = strcmp(name, machine);
  923. X    return(compare == 0 ? 0 : -1);
  924. X}
  925. X
  926. Xget_entry(machine, address, fileid, offset)
  927. Xchar *machine, *address;
  928. XFILE *fileid;
  929. Xlong offset;
  930. X{
  931. X    /** get entry...return machine and address immediately
  932. X        following given offset in fileid.  **/
  933. X
  934. X    (void) fseek(fileid, offset, 0);
  935. X
  936. X    /* To get to the beginning of a record, if we are not at offset 0,
  937. X     * read until we hit an end-of-line */
  938. X
  939. X    if(offset != 0L)
  940. X      while (getc(fileid) != '\n')
  941. X         ;
  942. X
  943. X    fscanf(fileid, "%s\t%s", machine, address);
  944. X}
  945. X
  946. Xinit_findnode()
  947. X{
  948. X    /** Initialize the FILE and 'size_of_file' values for the 
  949. X        findnode procedure **/
  950. X
  951. X    struct stat buffer;
  952. X    char   *path_filename;
  953. X
  954. X#ifdef USE_DBM
  955. X    char buf[BUFSIZ];
  956. X
  957. X    sprintf(buf,"%s.pag", pathfile);
  958. X    path_filename = buf;
  959. X#else
  960. X    path_filename = pathfile;
  961. X#endif
  962. X
  963. X    if (stat(path_filename, &buffer) == -1) {
  964. X      dprint(2, (debugfile, 
  965. X          "Warning: pathalias file \"%s\" wasn't found by %s\n", 
  966. X          path_filename, "init_findnode"));
  967. X      size_of_pathfd = 0;
  968. X      return;
  969. X    }
  970. X
  971. X    size_of_pathfd = (long) buffer.st_size;
  972. X
  973. X#ifdef USE_DBM
  974. X    
  975. X    if (dbminit(pathfile) != 0) {
  976. X      dprint(2, (debugfile,
  977. X         "Warning: couldn't initialize DBM database %s\n", 
  978. X         pathfile));
  979. X      dprint(2, (debugfile, "** %s - %s **\n\n", error_name(errno),
  980. X             error_description(errno)));
  981. X      size_of_pathfd = 0;    /* error flag, in this case */
  982. X      return;
  983. X    }
  984. X     
  985. X    return;
  986. X#else
  987. X
  988. X    if ((pathfd = fopen(pathfile,"r")) == NULL) {
  989. X      dprint(2, (debugfile,
  990. X        "Warning: Can't read pathalias file \"%s\" within %s\n", 
  991. X           pathfile, "init_findnode"));
  992. X      size_of_pathfd = 0;
  993. X    }
  994. X    else
  995. X      dprint(3, (debugfile, "\nOpened '%s' as pathalias database.\n\n", 
  996. X          pathfile));
  997. X#endif
  998. X}
  999. X
  1000. Xchar *find_path_to(machine, printf_format)
  1001. Xchar *machine;
  1002. Xint   printf_format;
  1003. X{
  1004. X    /** Returns either the path to the specified machine or NULL if
  1005. X        not found.  If "printf_format" is TRUE, then it leaves the
  1006. X        '%s' intact, otherwise it assumes that the address is a uucp
  1007. X        address for the domain expansion program and removes the
  1008. X        last three characters of the expanded name ("!%s") since
  1009. X        they're redundant with the expansion!
  1010. X        **/
  1011. X
  1012. X    static char buffer[SLEN];    /* space for path */
  1013. X
  1014. X    if (size_of_pathfd > 0)
  1015. X      if (binary_search(machine, buffer) != -1) {       /* found it! */
  1016. X        if (! printf_format && strlen(buffer) > 3)
  1017. X          buffer[strlen(buffer)-3] = '\0';
  1018. X        return( (char *) buffer);
  1019. X      }
  1020. X
  1021. X    return(NULL);                        /* failed if it's here! */
  1022. X}
  1023. SHAR_EOF
  1024. chmod 0444 src/aliasdb.c || echo "restore of src/aliasdb.c fails"
  1025. echo "x - extracting src/aliaslib.c (Text)"
  1026. sed 's/^X//' << 'SHAR_EOF' > src/aliaslib.c &&
  1027. X
  1028. Xstatic char rcsid[] = "@(#)$Id: aliaslib.c,v 2.5 89/03/25 21:45:46 syd Exp $";
  1029. X
  1030. X/*******************************************************************************
  1031. X *  The Elm Mail System  -  $Revision: 2.5 $   $State: Exp $
  1032. X *
  1033. X *             Copyright (c) 1986, 1987 Dave Taylor
  1034. X *             Copyright (c) 1988, 1989 USENET Community Trust
  1035. X *******************************************************************************
  1036. X * Bug reports, patches, comments, suggestions should be sent to:
  1037. X *
  1038. X *    Syd Weinstein, Elm Coordinator
  1039. X *    elm@dsinc.UUCP            dsinc!elm
  1040. X *
  1041. X *******************************************************************************
  1042. X * $Log:    aliaslib.c,v $
  1043. X * Revision 2.5  89/03/25  21:45:46  syd
  1044. X * Initial 2.2 Release checkin
  1045. X * 
  1046. X *
  1047. X ******************************************************************************/
  1048. X
  1049. X/** Library of functions dealing with the alias system...
  1050. X
  1051. X **/
  1052. X
  1053. X#include "headers.h"
  1054. X
  1055. Xchar *expand_group(), *get_alias_address(), *expand_system();
  1056. Xchar *get_token(), *strpbrk();
  1057. Xlong lseek();
  1058. X
  1059. Xchar *get_alias_address(name, mailing, depth)
  1060. Xchar *name;
  1061. Xint   mailing, depth;
  1062. X{
  1063. X    /** return the line from either datafile that corresponds 
  1064. X        to the specified name.  If 'mailing' specified, then
  1065. X        fully expand group names.  Depth specifies the nesting
  1066. X        depth - the routine should always initially be called
  1067. X        with this equal 0.  Returns NULL if not found   **/
  1068. X
  1069. X    static char buffer[VERY_LONG_STRING];
  1070. X    int    loc;
  1071. X
  1072. X    if (strlen(name) == 0)
  1073. X      return( (char *) NULL);
  1074. X
  1075. X    if (! read_in_aliases) {
  1076. X      read_alias_files();
  1077. X      read_in_aliases = TRUE;
  1078. X    }
  1079. X
  1080. X    if (user_files) 
  1081. X      if ((loc = find(name, user_hash_table, MAX_UALIASES)) >= 0) {
  1082. X        lseek(user_data, user_hash_table[loc].byte, 0L);
  1083. X        get_line(user_data, buffer);
  1084. X        if (buffer[0] == '!' && mailing)
  1085. X          return(expand_group(buffer, depth));
  1086. X        else if (strpbrk(buffer,"!@:") != NULL)    /* has a hostname */
  1087. X#ifdef DONT_TOUCH_ADDRESSES
  1088. X          return((char *) buffer);
  1089. X#else
  1090. X          return(expand_system(buffer, TRUE));
  1091. X#endif
  1092. X        else
  1093. X          return((char *) buffer);
  1094. X      }
  1095. X     
  1096. X    if (system_files) 
  1097. X      if ((loc = find(name, system_hash_table, MAX_SALIASES)) >= 0) {
  1098. X        lseek(system_data, system_hash_table[loc].byte, 0L);
  1099. X        get_line(system_data, buffer);
  1100. X        if (buffer[0] == '!' && mailing)
  1101. X          return(expand_group(buffer, depth));
  1102. X        else if (strpbrk(buffer,"!@:") != NULL)    /* has a hostname */
  1103. X#ifdef DONT_TOUCH_ADDRESSES
  1104. X          return((char *) buffer);
  1105. X#else
  1106. X          return(expand_system(buffer, TRUE));
  1107. X#endif
  1108. X        else
  1109. X          return((char *) buffer);
  1110. X      }
  1111. X    
  1112. X    return( (char *) NULL);
  1113. X}
  1114. X
  1115. Xchar *expand_system(buffer, show_errors)
  1116. Xchar *buffer;
  1117. Xint   show_errors;
  1118. X{
  1119. X    /** This routine will check the first machine name in the given path 
  1120. X        (if any) and expand it out if it is an alias...if not, it will 
  1121. X        return what it was given.  If show_errors is false, it won't 
  1122. X        display errors encountered...
  1123. X    **/
  1124. X
  1125. X    dprint(6, (debugfile, "expand_system(%s, show-errors=%s)\n", buffer,
  1126. X        onoff(show_errors)));
  1127. X    findnode(buffer, show_errors);
  1128. X
  1129. X    return( (char *) buffer);
  1130. X}
  1131. X          
  1132. Xchar *expand_group(members, depth)
  1133. Xchar *members;
  1134. Xint  depth;
  1135. X{
  1136. X    /** Given a group of names separated by commas, this routine
  1137. X        will return a string that is the full addresses of each
  1138. X        member separated by spaces. Depth is an internal counter
  1139. X        that keeps track of the depth of nesting that the routine
  1140. X        is in...it's for the get_token routine!  **/
  1141. X
  1142. X    static char buffer[VERY_LONG_STRING];
  1143. X    char   buf[LONG_STRING], *word, *address, *bufptr;
  1144. X    char   *strcpy();
  1145. X
  1146. X    strcpy(buf, members);             /* parameter safety! */
  1147. X    if (depth == 0) buffer[0] = '\0';    /* nothing in yet!   */
  1148. X    bufptr = (char *) buf;            /* grab the address  */
  1149. X    depth++;                /* one deeper!       */
  1150. X
  1151. X    while ((word = get_token(bufptr, "!, ", depth)) != NULL) {
  1152. X      if ((address = get_alias_address(word, 1, depth)) == NULL) {
  1153. X        if (! valid_name(word)) {
  1154. X          dprint(3, (debugfile, "Encountered illegal address %s in %s\n",
  1155. X            word, "expand_group"));
  1156. X          error1("%s is an illegal address!", word);
  1157. X          return( (char *) NULL);
  1158. X        }
  1159. X        else if (strcmp(buffer, word) != 0)
  1160. X          sprintf(buffer, "%s%s%s", buffer,
  1161. X            (strlen(buffer) > 0)? ", ":"", word);
  1162. X      }
  1163. X      else if (strcmp(buffer, address) != 0)
  1164. X        sprintf(buffer,"%s%s%s", buffer, 
  1165. X            (strlen(buffer) > 0)? ", ":"", address);
  1166. X
  1167. X      bufptr = NULL;
  1168. X    }
  1169. X
  1170. X    return( (char *) buffer);
  1171. X}
  1172. X
  1173. Xint
  1174. Xfind(word, table, size)
  1175. Xchar *word;
  1176. Xstruct alias_rec table[];
  1177. Xint size;
  1178. X{
  1179. X    /** find word and return loc, or -1 **/
  1180. X    register int loc;
  1181. X    
  1182. X    if (strlen(word) > 20) {
  1183. X      dprint(3, (debugfile, "Overly long alias name entered: %s\n", word));
  1184. X      error1("Bad alias name: %s.  Too long.\n", word);
  1185. X      return(-1);
  1186. X    }
  1187. X
  1188. X    loc = hash_it(word, size);
  1189. X
  1190. X    while (strcmp(word, table[loc].name) != 0) {
  1191. X      if (table[loc].name[0] == '\0')
  1192. X        return(-1);
  1193. X      loc = (loc + 1) % size; 
  1194. X    }
  1195. X
  1196. X    return(loc);
  1197. X}
  1198. X
  1199. Xint
  1200. Xhash_it(string, table_size)
  1201. Xchar *string;
  1202. Xint   table_size;
  1203. X{
  1204. X    /** compute the hash function of the string, returning
  1205. X        it (mod table_size) **/
  1206. X
  1207. X    register int i, sum = 0;
  1208. X    
  1209. X    for (i=0; string[i] != '\0'; i++)
  1210. X      sum += (int) string[i];
  1211. X
  1212. X    return(sum % table_size);
  1213. X}
  1214. X
  1215. Xget_line(fd, buffer)
  1216. Xint fd;
  1217. Xchar *buffer;
  1218. X{
  1219. X    /* Read from file fd.  End read upon reading either 
  1220. X       EOF or '\n' character (this is where it differs 
  1221. X       from a straight 'read' command!) */
  1222. X
  1223. X    register int i= 0;
  1224. X    char     ch;
  1225. X
  1226. X    while (read(fd, &ch, 1) > 0)
  1227. X      if (ch == '\n' || ch == '\r') {
  1228. X        buffer[i] = 0;
  1229. X        return;
  1230. X      }
  1231. X      else
  1232. X        buffer[i++] = ch;
  1233. X}
  1234. SHAR_EOF
  1235. chmod 0444 src/aliaslib.c || echo "restore of src/aliaslib.c fails"
  1236. echo "x - extracting src/args.c (Text)"
  1237. sed 's/^X//' << 'SHAR_EOF' > src/args.c &&
  1238. X
  1239. Xstatic char rcsid[] = "@(#)$Id: args.c,v 2.9 89/03/25 21:45:48 syd Exp $";
  1240. X
  1241. X/*******************************************************************************
  1242. X *  The Elm Mail System  -  $Revision: 2.9 $   $State: Exp $
  1243. X *
  1244. X *             Copyright (c) 1986, 1987 Dave Taylor
  1245. X *             Copyright (c) 1988, 1989 USENET Community Trust
  1246. X *******************************************************************************
  1247. X * Bug reports, patches, comments, suggestions should be sent to:
  1248. X *
  1249. X *    Syd Weinstein, Elm Coordinator
  1250. X *    elm@dsinc.UUCP            dsinc!elm
  1251. X *
  1252. X *******************************************************************************
  1253. X * $Log:    args.c,v $
  1254. X * Revision 2.9  89/03/25  21:45:48  syd
  1255. X * Initial 2.2 Release checkin
  1256. X * 
  1257. X *
  1258. X ******************************************************************************/
  1259. X
  1260. X/** starting argument parsing routines for ELM system...
  1261. X
  1262. X**/
  1263. X
  1264. X#include "headers.h"
  1265. X
  1266. X
  1267. Xextern char *optarg;        /* optional argument as we go */
  1268. Xextern int   optind;            /* argnum + 1 when we leave   */
  1269. X
  1270. Xvoid exit();    /* just keeping lint happy.... */
  1271. X
  1272. Xchar *
  1273. Xparse_arguments(argc, argv, to_whom)
  1274. Xint argc;
  1275. Xchar *argv[], *to_whom;
  1276. X{
  1277. X    /** Set flags according to what was given to program.  If we are 
  1278. X        fed a name or series of names, put them into the 'to_whom' buffer
  1279. X        and if the check_only flag wasn't presented, set mail_only to ON,
  1280. X        and if stdin is not a tty, set batch_only  to ON;
  1281. X        Return req_mfile, which points to a named mail file or is empty.
  1282. X        **/
  1283. X
  1284. X    register int c = 0;
  1285. X    char *strcpy();
  1286. X    static char req_mfile[SLEN];
  1287. X
  1288. X    to_whom[0] = '\0';
  1289. X    batch_subject[0] = '\0';
  1290. X
  1291. X        while ((c = getopt(argc, argv, "?acd:f:hkKms:Vwz")) != EOF) {
  1292. X       switch (c) {
  1293. X         case 'a' : arrow_cursor++;        break;
  1294. X         case 'c' : check_only++;        break;
  1295. X         case 'd' : debug = atoi(optarg);    break;
  1296. X         case 'f' : strcpy(req_mfile, optarg);    break;
  1297. X         case '?' :
  1298. X         case 'h' : args_help();
  1299. X         case 'k' : hp_terminal++;    break;
  1300. X         case 'K' : hp_terminal++; hp_softkeys++;    break;
  1301. X         case 'm' : mini_menu = 0;    break;
  1302. X         case 's' : strcpy(batch_subject, optarg);    break;
  1303. X             case 'V' : sendmail_verbose++;     break;
  1304. X         case 'w' : warnings = 0;    break;
  1305. X         case 'z' : check_size++;   break;
  1306. X        }
  1307. X     }
  1308. X
  1309. X
  1310. X#ifndef DEBUG
  1311. X    if (debug)
  1312. X      printf(
  1313. X     "Warning: system created without debugging enabled - request ignored\n");
  1314. X    debug = 0;
  1315. X#endif
  1316. X
  1317. X    if (optind < argc) {
  1318. X      while (optind < argc) {
  1319. X        if (strlen(to_whom) + strlen(to_whom[0] != '\0'? " " : "") +
  1320. X            strlen(argv[optind]) > SLEN)
  1321. X                exit(printf("\n\rToo many addresses, or addresses too long!\n\r"));
  1322. X
  1323. X        sprintf(to_whom, "%s%s%s", to_whom, 
  1324. X                to_whom[0] != '\0'? " " : "", argv[optind]);
  1325. X        if(!check_only)
  1326. X          mail_only++;
  1327. X        optind++;
  1328. X      }
  1329. X      check_size = 0;    /* NEVER do this if we're mailing!! */
  1330. X    }
  1331. X
  1332. X     if (strlen(batch_subject) > 0 && ! mail_only) 
  1333. X       exit(printf(
  1334. X     "\n\rDon't understand specifying a subject and no-one to send to!\n\r"));
  1335. X
  1336. X    if (!isatty(fileno(stdin)) && !check_only) {
  1337. X      batch_only = ON;
  1338. X      if(*batch_subject == '\0')
  1339. X        strcpy(batch_subject, DEFAULT_BATCH_SUBJECT);
  1340. X    }
  1341. X    return(req_mfile);
  1342. X
  1343. X
  1344. X}
  1345. X
  1346. Xargs_help()
  1347. X{
  1348. X    /**  print out possible starting arguments... **/
  1349. X
  1350. X    printf("\nPossible Starting Arguments for ELM program:\n\n");
  1351. X    printf("\targ\t\t\tMeaning\n");
  1352. X    printf("\t -a \t\tArrow - use the arrow pointer regardless\n");
  1353. X    printf("\t -c \t\tCheckalias - check the given aliases only\n");
  1354. X    printf("\t -dn\t\tDebug - set debug level to 'n'\n");
  1355. X    printf(
  1356. X      "\t -fx\t\tFolder - read folder 'x' rather than incoming mailbox\n");
  1357. X    printf("\t -h \t\tHelp - give this list of options\n");
  1358. X    printf("\t -k \t\tKeypad - enable HP 2622 terminal keyboard\n");
  1359. X    printf("\t -K \t\tKeypad&softkeys - enable use of softkeys + \"-k\"\n");
  1360. X    printf("\t -m \t\tMenu - Turn off menu, using more of the screen\n");
  1361. X    printf("\t -sx\t\tSubject 'x' - for batchmailing\n");
  1362. X        printf("\t -V \t\tEnable sendmail voyeur mode.\n");
  1363. X    printf("\t -w \t\tSupress warning messages...\n");
  1364. X    printf("\t -z \t\tZero - don't enter ELM if no mail is pending\n");
  1365. X    printf("\n");
  1366. X    printf("\n");
  1367. X    exit(1);
  1368. X}
  1369. SHAR_EOF
  1370. chmod 0444 src/args.c || echo "restore of src/args.c fails"
  1371. echo "x - extracting src/bouncebk.c (Text)"
  1372. sed 's/^X//' << 'SHAR_EOF' > src/bouncebk.c &&
  1373. X
  1374. Xstatic char rcsid[] = "@(#)$Id: bouncebk.c,v 2.3 89/03/25 21:45:49 syd Exp $";
  1375. X
  1376. X/*******************************************************************************
  1377. X *  The Elm Mail System  -  $Revision: 2.3 $   $State: Exp $
  1378. X *
  1379. X *             Copyright (c) 1986, 1987 Dave Taylor
  1380. X *             Copyright (c) 1988, 1989 USENET Community Trust
  1381. X *******************************************************************************
  1382. X * Bug reports, patches, comments, suggestions should be sent to:
  1383. X *
  1384. X *    Syd Weinstein, Elm Coordinator
  1385. X *    elm@dsinc.UUCP            dsinc!elm
  1386. X *
  1387. X *******************************************************************************
  1388. X * $Log:    bouncebk.c,v $
  1389. X * Revision 2.3  89/03/25  21:45:49  syd
  1390. X * Initial 2.2 Release checkin
  1391. X * 
  1392. X *
  1393. X ******************************************************************************/
  1394. X
  1395. X/** This set of routines implement the bounceback feature of the mailer.
  1396. X    This feature allows mail greater than 'n' hops away (n specified by
  1397. X    the user) to have a 'cc' to the user through the remote machine.  
  1398. X
  1399. X    Due to the vagaries of the Internet addressing (uucp -> internet -> uucp)
  1400. X    this will NOT generate bounceback copies with mail to an internet host!
  1401. X
  1402. X**/
  1403. X
  1404. X#include "headers.h"
  1405. X
  1406. Xchar *bounce_off_remote(),        /* forward declaration */
  1407. X     *strcat(), *strcpy();
  1408. X
  1409. Xint
  1410. Xuucp_hops(to)
  1411. Xchar *to;
  1412. X{    
  1413. X    /** Given the entire "To:" list, return the number of hops in the
  1414. X        first address (a hop = a '!') or ZERO iff the address is to a
  1415. X          non uucp address.
  1416. X    **/
  1417. X
  1418. X    register int hopcount = 0, iindex;
  1419. X
  1420. X    for (iindex = 0; ! whitespace(to[iindex]) && to[iindex] != '\0'; iindex++) {
  1421. X      if (to[iindex] == '!')
  1422. X        hopcount++;
  1423. X      else if (to[iindex] == '@' || to[iindex] == '%' || to[iindex] == ':')
  1424. X        return(0);    /* don't continue! */
  1425. X    }
  1426. X
  1427. X    return(hopcount);
  1428. X}
  1429. X    
  1430. Xchar *bounce_off_remote(to)
  1431. Xchar *to;
  1432. X{
  1433. X    /** Return an address suitable for framing (no, that's not it...)
  1434. X        Er, suitable for including in a 'cc' line so that it ends up
  1435. X        with the bounceback address.  The method is to take the first 
  1436. X        address in the To: entry and break it into machines, then 
  1437. X        build a message up from that.  For example, consider the
  1438. X        following address:
  1439. X            a!b!c!d!e!joe
  1440. X        the bounceback address would be;
  1441. X            a!b!c!d!e!d!c!b!a!ourmachine!ourname
  1442. X        simple, eh?
  1443. X    **/
  1444. X
  1445. X    static char address[LONG_STRING];    /* BEEG address buffer! */
  1446. X
  1447. X    char   host[MAX_HOPS][NLEN];    /* for breaking up addr */
  1448. X    register int hostcount = 0, hindex = 0, 
  1449. X           iindex;
  1450. X
  1451. X    for (iindex = 0; !whitespace(to[iindex]) && to[iindex] != '\0'; iindex++) {
  1452. X      if (to[iindex] == '!') {
  1453. X        host[hostcount][hindex] = '\0';
  1454. X        hostcount++;
  1455. X        hindex = 0;
  1456. X      }
  1457. X      else 
  1458. X        host[hostcount][hindex++] = to[iindex];
  1459. X    }
  1460. X
  1461. X    /* we have hostcount hosts... */
  1462. X
  1463. X    strcpy(address, host[0]);    /* initialize it! */
  1464. X
  1465. X    for (iindex=1; iindex < hostcount; iindex++) {
  1466. X      strcat(address, "!");
  1467. X      strcat(address, host[iindex]);
  1468. X    }
  1469. X    
  1470. X    /* and now the same thing backwards... */
  1471. X
  1472. X    for (iindex = hostcount -2; iindex > -1; iindex--) {
  1473. X      strcat(address, "!");
  1474. X      strcat(address, host[iindex]);
  1475. X    }
  1476. X
  1477. X    /* and finally, let's tack on our machine and login name */
  1478. X
  1479. X    strcat(address, "!");
  1480. X    strcat(address, hostname);
  1481. X    strcat(address, "!");
  1482. X    strcat(address, username);
  1483. X
  1484. X    /* and we're done!! */
  1485. X
  1486. X    return( (char *) address );
  1487. X}
  1488. SHAR_EOF
  1489. chmod 0444 src/bouncebk.c || echo "restore of src/bouncebk.c fails"
  1490. echo "x - extracting src/builtin.c (Text)"
  1491. sed 's/^X//' << 'SHAR_EOF' > src/builtin.c &&
  1492. X
  1493. Xstatic char rcsid[] = "@(#)$Id: builtin.c,v 2.23 89/03/25 21:45:51 syd Exp $";
  1494. X
  1495. X/*******************************************************************************
  1496. X *  The Elm Mail System  -  $Revision: 2.23 $   $State: Exp $
  1497. X *
  1498. X *             Copyright (c) 1986, 1987 Dave Taylor
  1499. X *             Copyright (c) 1988, 1989 USENET Community Trust
  1500. X *******************************************************************************
  1501. X * Bug reports, patches, comments, suggestions should be sent to:
  1502. X *
  1503. X *    Syd Weinstein, Elm Coordinator
  1504. X *    elm@dsinc.UUCP            dsinc!elm
  1505. X *
  1506. X *******************************************************************************
  1507. X * $Log:    builtin.c,v $
  1508. X * Revision 2.23  89/03/25  21:45:51  syd
  1509. X * Initial 2.2 Release checkin
  1510. X * 
  1511. X *
  1512. X ******************************************************************************/
  1513. X
  1514. X/** This is the built-in pager for displaying messages while in the Elm
  1515. X    program.  It's a bare-bones pager with precious few options. The idea
  1516. X    is that those systems that are sufficiently slow that using an external
  1517. X    pager such as 'more' is too slow, then they can use this!
  1518. X
  1519. X    Also added support for the "builtin+" pager (clears the screen for
  1520. X    each new page) including a two-line overlap for context...
  1521. X
  1522. X**/
  1523. X
  1524. X#include "headers.h"
  1525. X#include <ctype.h>
  1526. X
  1527. X#define  BEEP        007        /* ASCII Bell character */
  1528. X
  1529. Xstatic    unfilled_lines,
  1530. X    form_title;
  1531. X
  1532. Xint    lines_displayed,        /* total number of lines displayed      */
  1533. X    total_lines_to_display,        /* total number of lines in message     */
  1534. X    pages_displayed;         /* for the nth page titles and all      */
  1535. X
  1536. Xstart_builtin(lines_in_message)
  1537. Xint lines_in_message;
  1538. X{
  1539. X    /** clears the screen and resets the internal counters... **/
  1540. X
  1541. X    dprint(8,(debugfile, 
  1542. X        "displaying %d lines from message using internal pager\n",
  1543. X        lines_in_message));
  1544. X
  1545. X    unfilled_lines = LINES;
  1546. X    form_title = 1;
  1547. X    lines_displayed = 0;
  1548. X        pages_displayed = 1;
  1549. X
  1550. X    total_lines_to_display = lines_in_message;
  1551. X}
  1552. X
  1553. Xextern int tabspacing;
  1554. X
  1555. Xint
  1556. Xnext_line(inputptr, output, width)
  1557. Xchar **inputptr, *output;
  1558. Xregister unsigned width;
  1559. X{
  1560. X    /* Copy characters from input to output and copy
  1561. X     * remainder of output to output. In copying use ^X notation for
  1562. X     * control characters, '?' non-ascii characters, expand tabs
  1563. X     * to correct number of spaces till next tab stop.
  1564. X     * Column zero of the next line is considered to be the tab stop
  1565. X     * that follows the last one that fits on a line.
  1566. X     * Copy until newline/return encountered, null char encountered,
  1567. X     * width characters producted in output buffer.
  1568. X     * Formfeed is handled exceptionally. If encountered it
  1569. X     * is removed from input and 1 is returned. Otherwise 0 is returned.
  1570. X     */
  1571. X
  1572. X    register char *optr, *iptr;
  1573. X    register unsigned chars_output, nt;
  1574. X    int ret_val;
  1575. X
  1576. X    optr = output;
  1577. X    iptr = *inputptr;
  1578. X    chars_output = 0;
  1579. X
  1580. X    ret_val = 0;    /* presume no formfeed */
  1581. X    while(1) {
  1582. X
  1583. X      if(chars_output >= width) {        /* no more room on line */
  1584. X        *optr++ = '\n';
  1585. X        *optr++ = '\r';
  1586. X        /* if next input character is newline or return,
  1587. X         * we can skip over it since we are outputing a newline anyway */ 
  1588. X        if((*iptr == '\n') || (*iptr == '\r'))
  1589. X          iptr++;
  1590. X        break;        
  1591. X      } else if (*iptr == '\n' || *iptr == '\r') {    /*newline or return */
  1592. X        *optr++ = '\n';
  1593. X        *optr++ = '\r';
  1594. X        iptr++;
  1595. X        break;            /* end of line */
  1596. X      } else if(*iptr == '\f') {        /* formfeed */
  1597. X        /* if next input character is newline or return,
  1598. X         * we can skip over it since we are outputing a formfeed anyway */ 
  1599. X        if((*++iptr == '\n') || (*iptr == '\r'))
  1600. X          iptr++;
  1601. X        ret_val = 1;
  1602. X        break;            /* leave rest of screen clear */
  1603. X      } else if(*iptr == '\0') {        /* none left in input string */
  1604. X        break;
  1605. X      } else if(!isascii(*iptr)) {
  1606. X        *optr++ = '?';            /* non ascii */
  1607. X        *iptr++;
  1608. X        chars_output++;
  1609. X      } else if(*iptr == '\t') {        /* tab stop */
  1610. X        if((nt=next_tab(chars_output+1)) > width) {
  1611. X          *optr++ = '\n';        /* won't fit on this line - autowrap */
  1612. X          *optr++ = '\r';        /* tab by tabbing so-to-speak to 1st */
  1613. X          iptr++;            /* column of next line */
  1614. X          break;
  1615. X        } else {        /* will fit - output proper num of spaces */
  1616. X          while(chars_output < nt-1) {
  1617. X        chars_output++;
  1618. X        *optr++ = ' ';
  1619. X          }
  1620. X          iptr++;
  1621. X        }
  1622. X      } else if(isprint(*iptr)) {
  1623. X        *optr++ = *iptr++;            /* printing character */
  1624. X        chars_output++;
  1625. X      } else {            /* non-white space control character */
  1626. X        if(chars_output + 2 <= width) {
  1627. X          *optr++ = '^';    
  1628. X          *optr++ = (*iptr == '\177' ? '?' : *iptr + 'A' - 1);
  1629. X          iptr++;
  1630. X          chars_output += 2;
  1631. X        } else {            /* no space on line for both chars */
  1632. X          break;
  1633. X        }
  1634. X      }
  1635. X    }
  1636. X    *optr = '\0';
  1637. X    *inputptr = iptr;
  1638. X    return(ret_val);
  1639. X}
  1640. X
  1641. X
  1642. Xint
  1643. Xdisplay_line(input_line)
  1644. Xchar *input_line;
  1645. X{
  1646. X    /** Display the given line on the screen, taking into account such
  1647. X        dumbness as wraparound and such.  If displaying this would put
  1648. X        us at the end of the screen, put out the "MORE" prompt and wait
  1649. X        for some input.   Return non-zero if the user terminates the
  1650. X        paging (e.g. 'i') or zero if we should continue. Also, 
  1651. X            this will pass back the value of any character the user types in 
  1652. X        at the prompt instead, if needed... (e.g. if it can't deal with
  1653. X        it at this point)
  1654. X    **/
  1655. X    
  1656. X    char *pending, footer[SLEN], display_buffer[SLEN], ch;
  1657. X    int formfeed;
  1658. X
  1659. X    pending = input_line;
  1660. X    CarriageReturn();
  1661. X
  1662. X    do {
  1663. X
  1664. X      /* while there is more space on the screen - leave prompt line free */
  1665. X      while(unfilled_lines > 0) {
  1666. X
  1667. X        /* display a screen's lineful of the input line
  1668. X         * and reset pending to point to remainder of input line */
  1669. X        formfeed = next_line(&pending, display_buffer, COLUMNS);
  1670. X
  1671. X        if(*display_buffer == '\0') {    /* no line to display */
  1672. X          if(!formfeed)    /* no "formfeed" to display
  1673. X                      * need more lines for screen */
  1674. X        return(FALSE);
  1675. X        } else
  1676. X          Write_to_screen(display_buffer, 0);
  1677. X
  1678. X        /* if formfeed, clear remainder of screen */
  1679. X        if(formfeed) {
  1680. X          CleartoEOS();
  1681. X          unfilled_lines=0;
  1682. X        }
  1683. X        else
  1684. X          unfilled_lines--;
  1685. X
  1686. X        /* if screen is not full (leave room for prompt)
  1687. X         * but we've used up input line, return */
  1688. X
  1689. X        if(unfilled_lines > 0 && *pending == '\0')
  1690. X          return(FALSE);    /* we need more lines to fill screen */
  1691. X
  1692. X        /* otherwise continue to display next part of input line */
  1693. X      }
  1694. X
  1695. X      /* screen is now full - prompt for user input */
  1696. X      sprintf(footer,
  1697. X          ( (user_level == 0) ?
  1698. X  " There %s %d line%s left (%d%%). Press <space> for more, or 'i' to return. "
  1699. X          : (user_level == 1) ?
  1700. X  " %s%d line%s more (%d%%). Press <space> for more, 'i' to return. "
  1701. X          :
  1702. X  " %s%d line%s more (you've seen %d%%) "),
  1703. X           (user_level == 0 ?
  1704. X             (total_lines_to_display - lines_displayed == 1 ?
  1705. X             "is" : "are") : ""),
  1706. X           total_lines_to_display - lines_displayed,
  1707. X           plural(total_lines_to_display - lines_displayed),
  1708. X           (int)((100L * lines_displayed) / total_lines_to_display));
  1709. X      MoveCursor(LINES, 0);
  1710. X      StartBold();
  1711. X      Write_to_screen(footer, 0);
  1712. X      EndBold();
  1713. X
  1714. X      switch(ch = ReadCh()) {
  1715. X
  1716. X        case '\n':
  1717. X        case '\r':    /* scroll down a line */
  1718. X            unfilled_lines = 1;
  1719. X            ClearLine(LINES);
  1720. X            break;
  1721. X
  1722. X        case ' ':    /* scroll a screenful */
  1723. X            unfilled_lines = LINES;
  1724. X            if(clear_pages) {
  1725. X              ClearScreen();
  1726. X              MoveCursor(0,0);
  1727. X              CarriageReturn();
  1728. X
  1729. X              /* output title */
  1730. X              if(title_messages && filter) {
  1731. X                title_for_page(++pages_displayed);
  1732. X                unfilled_lines -= 2;
  1733. X              }
  1734. X            } else ClearLine(LINES);
  1735. X
  1736. X            /* and keep last line to be first line of next
  1737. X             * screenful unless we had a formfeed */
  1738. X            if(!formfeed) {
  1739. X              if(clear_pages)
  1740. X                Write_to_screen(display_buffer, 0);
  1741. X              unfilled_lines--;
  1742. X            }
  1743. X            break;
  1744. X
  1745. X        default:    return(ch);
  1746. X      }
  1747. X      CarriageReturn();
  1748. X    } while(*pending);
  1749. X    return(FALSE);
  1750. X}
  1751. X      
  1752. Xtitle_for_page(page)
  1753. Xint page;
  1754. X{
  1755. X    /** Output a nice title for the second thru last pages of the message 
  1756. X        we're currently reading. Note - this code is very similar to
  1757. X        that which produces the title for the first page, except that
  1758. X        page number replaces the date and the method by which it
  1759. X        gets to the screen **/
  1760. X
  1761. X    static char title1[SLEN], title2[SLEN];
  1762. X    char titlebuf[SLEN], title3[SLEN], who[SLEN];
  1763. X    static t1_len, t2_len;
  1764. X    register int padding, showing_to;
  1765. X
  1766. X    /* format those parts of the title that are constant for a message */
  1767. X    if(form_title) {
  1768. X
  1769. X      showing_to = tail_of(headers[current-1]->from, who,
  1770. X        headers[current-1]->to);
  1771. X
  1772. X      sprintf(title1, "%s %d/%d  ",
  1773. X          headers[current-1]->status & DELETED ? "[deleted]" :
  1774. X          headers[current-1]->status & FORM_LETTER ? "Form": "Message",
  1775. X          current, message_count);
  1776. X      t1_len = strlen(title1);
  1777. X      sprintf(title2, "%s %s", showing_to? "To" : "From", who);
  1778. X      t2_len = strlen(title2);
  1779. X    }
  1780. X    /* format those parts of the title that vary between pages of a mesg */
  1781. X    sprintf(title3, "  Page %d", page);
  1782. X
  1783. X    /* truncate or pad title2 portion on the right
  1784. X     * so that line fits exactly to the rightmost column */
  1785. SHAR_EOF
  1786. echo "End of part 11"
  1787. echo "File src/builtin.c is continued in part 12"
  1788. echo "12" > s2_seq_.tmp
  1789. exit 0
  1790.  
  1791.